package com.devilvan.betrice.request.component;

import com.devilvan.betrice.exception.constant.BetriceExceptionConstant;
import com.devilvan.betrice.proxy.BetriceHttpProxy;
import com.devilvan.betrice.request.BetriceHttpBuilder;
import com.devilvan.betrice.request.pojo.BetriceHttpClient;
import com.devilvan.betrice.util.UEmpty;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author Evad.Wu
 * @Description 生成HttpClient组件
 * @date 2022-07-06
 */
@Slf4j
@Component
public class HttpClientComponent {
    @Resource(name = "httpClientPool")
    private PoolingHttpClientConnectionManager connectionManager;
    @Resource(name = "betriceRequestConfig")
    private RequestConfig requestConfig;
    @Resource(name = "httpClientRetryHandler")
    private HttpClientRetryHandler httpClientRetryHandler;

    /**
     * 步骤一：生成一个 HttpRequest请求对象
     *
     * @param requestMethod 请求方式 {@link RequestMethod}
     * @param url           请求路径
     * @param header        输入的头信息
     * @param isProxy       是否需要代理
     * @return 返回请求对象
     */
    public HttpRequestBase generateHttpRequest(RequestMethod requestMethod, String url) {
        return generateHttpRequest(requestMethod, url, null);
    }

    public HttpRequestBase generateHttpRequest(RequestMethod requestMethod, String url, Map<String, String> header) {
        HttpRequestBase httpRequestBase = BetriceHttpBuilder.requestMethod2HttpRequestBase(requestMethod, url);
        if (UEmpty.isNotEmpty(header)) {
            Set<Map.Entry<String, String>> entrySet = header.entrySet();
            for (Map.Entry<String, String> entry : entrySet) {
                httpRequestBase.setHeader(entry.getKey(), entry.getValue());
            }
        }
        return httpRequestBase;
    }

    /**
     * 重构步骤三：通过 {@link BetriceHttpBuilder} 构建的httpclient提供请求方法对象以及
     *
     * @param betriceHttpClient {@link BetriceHttpBuilder} 构建的httpclient
     * @return 请求返回的报文
     */
    public String doExecute(BetriceHttpClient betriceHttpClient) {
        // 代理对象
        BetriceHttpProxy httpProxy = betriceHttpClient.getHttpProxy();
        List<HttpHost> proxyHost = null;
        if (Optional.ofNullable(httpProxy).isPresent()) {
            proxyHost = httpProxy.getProxyHost();
        }
        HttpClientBuilder httpClientBuilder = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .setRetryHandler(httpClientRetryHandler)
                .setConnectionManager(connectionManager);
        if (UEmpty.isNotEmpty(proxyHost)) {
            httpClientBuilder.setProxy(proxyHost.get(0)).setDefaultCredentialsProvider(betriceHttpClient.getCredentialsProvider());
        }
        CloseableHttpClient client = httpClientBuilder.build();
        String resJson = null;
        CloseableHttpResponse response = null;
        try {
            response = client.execute(betriceHttpClient.getHttpRequest());
            HttpEntity responseEntity = response.getEntity();
            resJson = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(BetriceExceptionConstant.INTERNAL_SERVER_EXP.getMessage());
        } finally {
            try {
                if (null != response) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resJson;
    }
}
